﻿// Copyright (c) Yoganand R. All rights reserved.
// For continued development and updates, visit http://yogsbreath.com
using System;
using System.Web.UI;
using System.Reflection;
using System.Collections.Specialized;

namespace MVCnExt.Web.UI.Ext
{
    /// <summary>
    /// Class used when Page.Form is null (MVC Applications) because there's no &lt;form runat=server&gt;
    /// </summary>
    internal class FormlessClientScriptManager : ClientScriptManagerWrapper
    {
        public FormlessClientScriptManager(Page page) : base(page) 
        {
            // because there's no <form runat=server> we have to manually render 
            // all registered scripts in the header
            page.Header.SetRenderMethodDelegate(RenderHtmlHead);
        }

        protected override void RenderClientCssInclude(string url)
        {
            //don't do anything, we're using SetRenderMethodDelegate
            return;
        }

        /// <summary>
        /// Renders all registered script objects in the HtmlHead object. This requires
        /// an &lt;head&gt; element defined with runat=server
        /// </summary>
        /// <param name="output">the output stream</param>
        /// <param name="container">the head control (element)</param>
        private void RenderHtmlHead(HtmlTextWriter output, Control container)
        {
            //manually render the begin tag
            output.RenderBeginTag(HtmlTextWriterTag.Head);
            
            //render script stuff
            ClientScriptManager script = container.Page.ClientScript;
            Type scriptType = script.GetType();
            Type[] argTypes = new Type[] { typeof(HtmlTextWriter) };

            // we could write our own register and render methods, which would work better in hosted environments
            // but for now this will save some time until that is needed
            MethodInfo renderBlocks = scriptType.GetMethod("RenderClientScriptBlocks", BindingFlags.NonPublic | BindingFlags.Instance, null, argTypes, null);
            MethodInfo renderStartUp = scriptType.GetMethod("RenderClientStartupScripts", BindingFlags.NonPublic | BindingFlags.Instance, null, argTypes, null);
            MethodInfo renderArrays = scriptType.GetMethod("RenderArrayDeclares", BindingFlags.NonPublic | BindingFlags.Instance, null, argTypes, null);
            
            Object[] args = new Object[]{output};
            
            renderBlocks.Invoke(script, args);
            renderArrays.Invoke(script, args);
            renderStartUp.Invoke(script, args);
            
            //render CssIncludes
            ListDictionary cssIncludes = base.GetClientCssIncludes();
            foreach (String url in cssIncludes.Values)
            {
                output.AddAttribute(HtmlTextWriterAttribute.Rel, "stylesheet");
                output.AddAttribute(HtmlTextWriterAttribute.Type, "text/css");
                output.AddAttribute(HtmlTextWriterAttribute.Href, url);
                output.RenderBeginTag(HtmlTextWriterTag.Link);
                output.RenderEndTag();
            }

            //manually render children after script blocks so custom code can reference included scripts
            foreach (Control control in container.Controls)
            {
                control.RenderControl(output);
            }

            //close the head element
            output.RenderEndTag();
        }
    }
}
